#include "direct_io_strategy.h"

#include <cstdlib>
#include <cstring>
#include <stdexcept>
#include <syslog.h>

// 平台特定的头文件
#ifdef _WIN32
#include <windows.h>
#include <fileapi.h>
#else
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#endif
#include "system_log_error_code.h"
namespace Base {
namespace SystemLog {

// Windows平台的内存对齐分配和释放函数
#ifdef _WIN32
namespace {
void* AlignedAllocWindows(size_t alignment, size_t size) {
    return _aligned_malloc(size, alignment);
}

void AlignedFreeWindows(void* ptr) {
    _aligned_free(ptr);
}
} // namespace
#endif

DirectIOStrategy::DirectIOStrategy(const DirectIOOptions &options)
    : FileOutputStrategy(options), dioOptions_(options)
#ifdef _WIN32
    , buffer_(nullptr, &AlignedFreeWindows)
#else
    , buffer_(nullptr, &std::free)
#endif
{
    // 确保缓冲区大小是对齐的倍数
    if (dioOptions_.bufferSize % dioOptions_.alignment != 0) {
        dioOptions_.bufferSize = 
            (dioOptions_.bufferSize / dioOptions_.alignment + 1) * dioOptions_.alignment;
    }

    // 分配对齐的内存
#ifdef _WIN32
    void* alignedMemory = AlignedAllocWindows(dioOptions_.alignment, dioOptions_.bufferSize);
#else
    void* alignedMemory = std::aligned_alloc(dioOptions_.alignment, dioOptions_.bufferSize);
#endif
    
    if (!alignedMemory) {
        throw std::runtime_error("Failed to allocate aligned memory for DirectIO");
    }
    buffer_.reset(static_cast<char*>(alignedMemory));

    // 验证对齐
    if (reinterpret_cast<uintptr_t>(buffer_.get()) % dioOptions_.alignment != 0) {
        throw std::runtime_error("DirectIO buffer not aligned");
    }
}

DirectIOStrategy::~DirectIOStrategy()
{
    Close();
}

#ifdef _WIN32
DWORD DirectIOStrategy::GetWindowsFlags() const
{
    DWORD flags = FILE_ATTRIBUTE_NORMAL;

    // 添加无缓冲和直接写入标志
    flags |= FILE_FLAG_NO_BUFFERING;
    flags |= FILE_FLAG_WRITE_THROUGH;

    return flags;
}
#else
int DirectIOStrategy::GetUnixFlags() const
{
    int flags = O_WRONLY | O_CREAT;

    // 添加直接IO标志
    flags |= O_DIRECT;

    return flags;
}
#endif

ErrCode DirectIOStrategy::OpenFile()
{
    auto fileName = GenerateFileName();
    
#ifdef _WIN32
    // Windows实现
    HANDLE hFile = CreateFileA(fileName.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, GetWindowsFlags(), NULL);

    if (hFile == INVALID_HANDLE_VALUE) {
        syslog(LOG_ERR, "Failed to open file: %lu", GetLastError());
        return ERR_FILE_OPEN_FAILED;
    }

    fileDescriptor_ = reinterpret_cast<intptr_t>(hFile);
#else
    // Unix实现
    fileDescriptor_ = open(fileName.c_str(), GetUnixFlags(), 0644);

    if (fileDescriptor_ < 0) {
        // 如果O_DIRECT失败，尝试普通模式
        syslog(LOG_WARNING, "O_DIRECT failed, fallback to normal mode: %s", strerror(errno));
        fileDescriptor_ = open(fileName.c_str(), O_WRONLY | O_CREAT, 0644);
    }

    if (fileDescriptor_ < 0) {
        syslog(LOG_ERR, "Failed to open file: %s", strerror(errno));
        return ERR_FILE_OPEN_FAILED;
    }
#endif

    // 获取文件大小
#ifdef _WIN32
    LARGE_INTEGER size;
    if (GetFileSizeEx(reinterpret_cast<HANDLE>(fileDescriptor_), &size)) {
        currentSize_ = static_cast<size_t>(size.QuadPart);
    } else {
        currentSize_ = 0;
    }
#else
    struct stat st;
    if (fstat(fileDescriptor_, &st) == 0) {
        currentSize_ = static_cast<size_t>(st.st_size);
    } else {
        currentSize_ = 0;
    }
#endif

    bufferOffset_ = 0;
    return ERR_OK;
}

ErrCode DirectIOStrategy::Write(const char* data, size_t len)
{
    std::lock_guard<std::mutex> lock(mutex_);

    if (fileDescriptor_ < 0) {
        return ERR_FILE_NOT_OPEN;
    }

    auto err = RollFileIfNeeded(len);
    if (err != ERR_OK) {
        return err;
    }

    const char* src = data;
    size_t remaining = len;

    // 处理大于缓冲区的数据
    if (remaining >= dioOptions_.bufferSize) {
        // 先刷新当前缓冲区
        err = FlushBuffer();
        if (err != ERR_OK) {
            return err;
        }

        // 直接写入对齐的数据块
        size_t alignedSize = (remaining / dioOptions_.alignment) * dioOptions_.alignment;
        if (alignedSize > 0) {
            err = WriteAligned(src, alignedSize);
            if (err != ERR_OK) {
                return err;
            }

            src += alignedSize;
            remaining -= alignedSize;
            currentSize_ += alignedSize;
        }
    }

    // 剩余数据放入缓冲区
    while (remaining > 0) {
        size_t copySize = std::min(dioOptions_.bufferSize - bufferOffset_, remaining);
        memcpy(buffer_.get() + bufferOffset_, src, copySize);
        bufferOffset_ += copySize;
        src += copySize;
        remaining -= copySize;

        if (bufferOffset_ == dioOptions_.bufferSize) {
            err = FlushBuffer();
            if (err != ERR_OK) {
                return err;
            }
        }
    }

    return ERR_OK;
}

ErrCode DirectIOStrategy::WriteAligned(const char* data, size_t size)
{
    // 确保数据是对齐的
    if (reinterpret_cast<uintptr_t>(data) % dioOptions_.alignment != 0) {
        return ERR_MEMORY_NOT_ALIGNED;
    }

    if (size % dioOptions_.alignment != 0) {
        return ERR_SIZE_NOT_ALIGNED;
    }

#ifdef _WIN32
    DWORD bytesWritten = 0;
    BOOL success = WriteFile(
        reinterpret_cast<HANDLE>(fileDescriptor_),
        data,
        static_cast<DWORD>(size),
        &bytesWritten,
        NULL
    );

    if (!success || bytesWritten != size) {
        return ERR_IO_WRITE_FAILED;
    }
#else
    ssize_t written = write(fileDescriptor_, data, size);
    if (written != static_cast<ssize_t>(size)) {
        return ERR_IO_WRITE_FAILED;
    }
#endif

    return ERR_OK;
}

ErrCode DirectIOStrategy::Flush()
{
    std::lock_guard<std::mutex> lock(mutex_);
    return FlushBuffer();
}

ErrCode DirectIOStrategy::Close()
{
    std::lock_guard<std::mutex> lock(mutex_);
    FlushBuffer();
    
#ifdef _WIN32
    if (fileDescriptor_ >= 0) {
        CloseHandle(reinterpret_cast<HANDLE>(fileDescriptor_));
        fileDescriptor_ = -1;
    }
#endif
    
    return FileOutputStrategy::CloseCurrentFile();
}

ErrCode DirectIOStrategy::FlushBuffer()
{
    if (bufferOffset_ == 0) {
        return ERR_OK;
    }

    // 确保写入大小是对齐的
    size_t alignedSize = (bufferOffset_ + dioOptions_.alignment - 1) / dioOptions_.alignment * dioOptions_.alignment;

    // 将缓冲区剩余部分清零，避免写入垃圾数据
    if (alignedSize > bufferOffset_) {
        memset(buffer_.get() + bufferOffset_, 0, alignedSize - bufferOffset_);
    }

#ifdef _WIN32
    DWORD bytesWritten = 0;
    BOOL success = WriteFile(reinterpret_cast<HANDLE>(fileDescriptor_), buffer_.get(), static_cast<DWORD>(alignedSize),
        &bytesWritten, NULL);

    if (!success || bytesWritten != alignedSize) {
        return ERR_IO_WRITE_FAILED;
    }
#else
    ssize_t written = write(fileDescriptor_, buffer_.get(), alignedSize);
    if (written != static_cast<ssize_t>(alignedSize)) {
        return ERR_IO_WRITE_FAILED;
    }
#endif

    bufferOffset_ = 0;
    return ERR_OK;
}
} // namespace SystemLog
} // namespace Base